﻿using Furion;
using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using LimaLims.Application.Service.Basic.Dto;
using LimaLims.Application.Service.TestCenter.Dto;
using LimaLims.Core;
using LimaLims.Core.Entity.Basic;
using LimaLims.Core.Entity.Experiment;
using LimaLims.Core.Entity.TestCenter;
using LimaLims.Core.Enum;
using LimaLims.Core.Util;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using MiniSoftware;

namespace LimaLims.Application.Service.TestCenter
{
    /// <summary>
    ///试验任务服务API
    /// </summary>
    [ApiDescriptionSettings(Name = "ExperimentTask", Order = 158)]
    [Route("api")]
    public class ExperimentTaskService : IExperimentTaskService, IDynamicApiController, ITransient
    {
        private readonly IRepository<ExperimentPlan> _experimentPlanRep;
        private readonly IRepository<ExperimentTask> _experimentTaskRep;
        private readonly IRepository<InspectionData> _inspectionDataRep;//试验项与规则
        private readonly IRejectDealService _rejectDealServiceRep;//不良品处理接口
        private readonly IRepository<TransformationRatio> _transformationRatioRep;  // 变比试验
        private readonly IRepository<DcResistance> _dcResistanceRep;//直阻试验
        private readonly IRepository<LoadTest> _loadTestRep;//负载试验
        private readonly IRepository<NoLoadTest> _noLoadTestRep;//空载试验
        private readonly IRepository<ChromTest> _chromTestRep;//绝缘油色谱试验
        private readonly IRepository<InsulationResistance> _insulationResistanceRep;//绝缘电阻试验
        private readonly IRepository<AcsdTest> _acsdTestRep;//感应耐压试验
        private readonly IRepository<PfwvTest> _pfwvRep;//工频耐压试验
        private readonly IRepository<Product> _productRep;//产品
        private readonly IRepository<ProductCategory> _productCategoryRep;//产品分类

        /// <summary>
        /// 构造函数
        /// </summary>
        public ExperimentTaskService(IRepository<ExperimentPlan> experimentPlanRep, IRepository<ExperimentTask> experimentTaskRep, IRepository<InspectionData> inspectionDataRep, IRejectDealService rejectDealServiceRep, IRepository<TransformationRatio> transformationRatioRep, IRepository<DcResistance> dcResistanceRep, IRepository<LoadTest> loadTestRep, IRepository<NoLoadTest> noLoadTestRep, IRepository<ChromTest> chromTestRep, IRepository<InsulationResistance> insulationResistanceRep, IRepository<AcsdTest> acsdTestRep, IRepository<PfwvTest> pwdvTestRep, IRepository<Product> productRep, IRepository<ProductCategory> productCategoryRep)
        {
            _experimentPlanRep = experimentPlanRep;
            _experimentTaskRep = experimentTaskRep;//试验任务
            _inspectionDataRep = inspectionDataRep;
            _rejectDealServiceRep = rejectDealServiceRep;
            _transformationRatioRep = transformationRatioRep;
            _dcResistanceRep = dcResistanceRep;
            _loadTestRep = loadTestRep;
            _noLoadTestRep = noLoadTestRep;
            _chromTestRep = chromTestRep;
            _insulationResistanceRep = insulationResistanceRep;
            _acsdTestRep = acsdTestRep;
            _pfwvRep = pwdvTestRep;
            _productRep = productRep;
            _productCategoryRep = productCategoryRep;
        }

        /// <summary>
        /// 任务详细
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("experimentTask/detail")]
        public async Task<ExperimentTaskDetail> Detail(long id)
        {
            var experimentTask = await _experimentTaskRep.DetachedEntities.Include(s => s.ExperimentPlan).ThenInclude(s => s.InspectionScheme).FirstOrDefaultAsync(u => u.Id == id);
            if (experimentTask == null)
                throw Oops.Oh("不存在此数据！");

            ExperimentTaskDetail detail = new ExperimentTaskDetail();

            detail.ExperimentTask = new ExperimentTaskOutput
            {
                Id = experimentTask.Id,
                ExperimentPlanId = experimentTask.ExperimentPlanId,
                ExperimentPlanCode = experimentTask.ExperimentPlan.Code,
                InspectionSchemeName = experimentTask.ExperimentPlan.InspectionScheme.Name,
                TaskCode = experimentTask.TaskCode,
                ExperimentUserId = experimentTask.ExperimentUserId,
                ExperimentUserName = experimentTask.ExperimentUserName,
                Type = experimentTask.TaskType,
                PlanStartTime = experimentTask.PlanStartTime.Date,
                PlanEndTime = experimentTask.PlanEndTime.Date,
                ActualEndTime = experimentTask.ActualEndTime,
                ActualStartTime = experimentTask.ActualStartTime,
                TargetId = experimentTask.TargetId,
                TargetCode = experimentTask.TargetCode,
                TargetName = experimentTask.TargetName,
                FactoryNumbe=experimentTask.FactoryNumbe,
                Status = experimentTask.Status,
                Result = experimentTask.Result,
                CreatedTime = experimentTask.CreatedTime.Value,
                TeamName = experimentTask.TeamName,
                ReportUrl= experimentTask.ReportUrl,
            };

            detail.InspectionTableData = await _inspectionDataRep.DetachedEntities.Where(s => s.InspectionSchemeId == experimentTask.ExperimentPlan.InspectionSchemeId).Select(u => new InspectionDataOutput
            {
                Id = u.Id,
                Code = u.Code,
                InspectionName = u.InspectionName,
                Remark = u.Remark,
                InspectionSchemeId = u.InspectionSchemeId,
                InspectionType = u.InspectionType,
                NsLowerLimit = u.NsLowerLimit,
                SjLowerLimit = u.SjLowerLimit,
                NsUpperLimit = u.NsUpperLimit,
                SjTargetValue = u.SjTargetValue,
                SjUpperLimit = u.SjUpperLimit,
                NsTargetValue = u.NsTargetValue,
            }).ToListAsync();

            return detail;
        }

        /// <summary>
        /// 分页数据
        /// </summary>
        [HttpGet("experimentTask/page")]
        public async Task<PageResult<ExperimentTaskOutput>> QueryPage([FromQuery] ExperimentTaskPageInput input)
        {
            var taskCode = !string.IsNullOrEmpty(input.TaskCode?.Trim());
            var experimentPlanCode = !string.IsNullOrEmpty(input.ExperimentPlanCode?.Trim());
            var experimentUserName = !string.IsNullOrEmpty(input.ExperimentUserName?.Trim());
            var status = input.Status.HasValue ? input.Status.Value : ExperimentStatus.NotStarted;
            var items = await _experimentTaskRep.DetachedEntities.Include(s => s.ExperimentPlan).ThenInclude(s => s.InspectionScheme)
                                         .Where((taskCode, u => EF.Functions.Like(u.TaskCode, $"%{input.TaskCode.Trim()}%")))
                                         .Where((experimentUserName, u => EF.Functions.Like(u.ExperimentUserName, $"%{input.ExperimentUserName.Trim()}%")))
                                         .Where((experimentPlanCode, u => EF.Functions.Like(u.ExperimentPlan.Code, $"%{input.ExperimentPlanCode.Trim()}%")))
                                         .Where(input.ExperimentUserId.HasValue, u => u.ExperimentUserId == input.ExperimentUserId)
                                         .Where(input.TeamId.HasValue, u => u.TeamId == input.TeamId)
                                         .Where(input.InspectionSchemeId.HasValue, u => u.ExperimentPlan.InspectionSchemeId == input.InspectionSchemeId)
                                         .Where(input.Result.HasValue, u => u.Result == input.Result)
                                         .Where(u => u.Status == status)
                                         .OrderByDescending(u => u.CreatedTime)
                                         .Select(u => new ExperimentTaskOutput
                                         {
                                             Id = u.Id,
                                             ExperimentPlanCode = u.ExperimentPlan.Code,
                                             InspectionSchemeName = u.ExperimentPlan.InspectionScheme.Name,
                                             TaskCode = u.TaskCode,
                                             ExperimentUserId = u.ExperimentUserId,
                                             ExperimentUserName = u.ExperimentUserName,
                                             Type = u.TaskType,
                                             PlanStartTime = u.PlanStartTime.Date,
                                             PlanEndTime = u.PlanEndTime.Date,
                                             ActualEndTime = u.ActualEndTime,
                                             ActualStartTime = u.ActualStartTime,
                                             TargetId = u.TargetId,
                                             TargetCode = u.TargetCode,
                                             FactoryNumbe = u.FactoryNumbe,
                                             TargetName = u.TargetName,
                                             Status = u.Status,
                                             Result = u.Result,
                                             CreatedTime = u.CreatedTime.Value,
                                             TeamName = u.TeamName,
                                             ReportUrl = u.ReportUrl,
                                         }).ToADPagedListAsync(input.PageNo, input.PageSize);

            return items;
        }

        /// <summary>
        /// 开工
        /// </summary>
        [HttpGet("experimentTask/startwork")]
        [UnitOfWork]
        public async Task Startwork(long id)
        {
            var experimentTask = await _experimentTaskRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == id);
            if (experimentTask == null)
                throw Oops.Oh("不存在此数据！");
            //更新任务开工信息
            experimentTask.Status = ExperimentStatus.Doing;
            experimentTask.ActualStartTime = DateTime.Now;
            experimentTask.ExperimentUserId = CurrentUserInfo.UserId;
            experimentTask.ExperimentUserName = CurrentUserInfo.Name;

            // 更新试验计划状态
            var experimentPlan = await _experimentPlanRep.DetachedEntities.FirstOrDefaultAsync(s => s.Id == experimentTask.ExperimentPlanId);
            if (experimentPlan.PlanStatus != ExperimentPlanStatus.Started)
            {
                experimentPlan.PlanStatus = ExperimentPlanStatus.Started;
                await _experimentPlanRep.UpdateIncludeAsync(entity: experimentPlan, new[] { nameof(ExperimentPlan.PlanStatus) });
            }
            await experimentTask.UpdateAsync();
        }

        /// <summary>
        /// 打印报告
        /// </summary>
        [HttpGet("experimentTask/printReport")]
        public async Task<string> PrintReport(long taskId, long productId, string taskCode)
        {
            PrintTemplate printTemplate = new PrintTemplate();

            var product = await _productRep.DetachedEntities.Include(s=>s.ProjectDrawing).Include(s => s.Category).ThenInclude(s => s.PrintTemplate)
                .FirstOrDefaultAsync(u => u.Id == productId);
            if (product == null)
                throw Oops.Oh("不存在此产品数据！");

            var experimentTask = await _experimentTaskRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == taskId);
            if (experimentTask == null)
                throw Oops.Oh("不存在此试验任务！");

            if (product.Category.PrintTemplateId.HasValue)
            {
                printTemplate = product.Category.PrintTemplate;
            }
            else
            {
                var categorys = _productCategoryRep.DetachedEntities.Include(s => s.PrintTemplate).Where(s => product.Category.Pids.Contains(s.Id.ToString())).ToList();

                printTemplate = GetMenuHierarchy(categorys, product.Category);
            }

            if (printTemplate == null)
            {
                throw Oops.Oh("此次试验任务产品未设置对应的打印模板！");
            }

            //获取模板路径
            //E:\LimaLims\lima-lims\LimaLims.Web.Entry\wwwroot
            //E:\LimaLims\lima-lims\LimaLims.Web.Entry\wwwroot/template/142307070918780/20241202/618351279763525.docx
            var templatePath = Path.Combine(App.WebHostEnvironment.WebRootPath + "/" + printTemplate.TemplateFile);
            //生成模板路径
            var reportUrl = $"/report/{product.FactoryNumbe}-{taskCode}.docx";
            var reportPath = Path.Combine(App.WebHostEnvironment.WebRootPath + reportUrl);

            //存在先删除再创建新的文件
            //var filePath = Path.Combine(App.WebHostEnvironment.WebRootPath, reportPath);
            //if (System.IO.File.Exists(filePath))
            //    System.IO.File.Delete(filePath);

            var value = new Dictionary<string, object>()
            {
                ["ProducName"] = product.Name,
                ["Specification"] = product.ProjectDrawing.Specification,
                ["FactoryNumbe"] = product.FactoryNumbe,
                ["RatedCapacity"] = product.ProjectDrawing.RatedCapacity,
                ["ProductSymbol"]=product.ProjectDrawing.ProductSymbol,//产品代号
                ["lqfs"] = product.ProjectDrawing.CoolingMode,//冷却方式
            };

            MiniWord.SaveAsByTemplate(reportPath, templatePath, value);

            experimentTask.ReportUrl = reportUrl;

            await _experimentTaskRep.UpdateIncludeAsync(experimentTask, new[] { nameof(ExperimentTask.ReportUrl)});

            return reportUrl;
        }

        //反递归查询产品分类设置的打印模板
        private static PrintTemplate GetMenuHierarchy(List<ProductCategory> categorys, ProductCategory current)
        {
            //递归查询父级菜单
            var parent = categorys.FirstOrDefault(m => m.Id == current.ParentId);
            //如果父级菜单不为空
            if (!parent.PrintTemplateId.HasValue)
            {
                //递归查询父级菜单的父级菜单
                var parentHierarchy = GetMenuHierarchy(categorys, parent);
                //返回父级菜单的父级菜单+当前菜单
                return current.PrintTemplate;
            }
            else
            {
                //如果父级为空，直接返回当前菜单
                return parent.PrintTemplate;
            }

        }

        /// <summary>
        /// 获取任务进度
        /// </summary>
        [HttpGet("experimentTask/getExperimentTaskStepDetail")]
        public async Task<List<ExperimentTaskStepDetail>> GetTaskStepDetail(long id)
        {
            return await GetTaskSteps(id);
        }

        [NonAction]
        private async Task<List<ExperimentTaskStepDetail>> GetTaskSteps(long id)
        {
            List<ExperimentTaskStepDetail> items = new List<ExperimentTaskStepDetail>();

            var experimentTask = await _experimentTaskRep.DetachedEntities.Include(s => s.ExperimentPlan).FirstOrDefaultAsync(u => u.Id == id);
            if (experimentTask == null)
                throw Oops.Oh("不存在此数据！");

            var inspectionTypes = _inspectionDataRep.DetachedEntities.Where(s => s.InspectionSchemeId == experimentTask.ExperimentPlan.InspectionSchemeId).Select(s => s.InspectionType).Distinct();

            foreach (var inspectionType in inspectionTypes)
            {
                ExperimentTaskStepDetail detail = new ExperimentTaskStepDetail();
                detail.InspectionType = inspectionType;
                switch (inspectionType)
                {
                    //直阻试验
                    case InspectionType.DcResistance:
                        var dcResistances = _dcResistanceRep.DetachedEntities.Where(s => s.ExperimentTaskId == id).ToList();
                        detail.SetpName = inspectionType.GetDescription();
                        detail.IsCompleted = dcResistances.Count > 0;
                        detail.IsPass = dcResistances.Where(s => s.Result == ExperimentResult.NoPass).Count() > 0 ? false : true;
                        items.Add(detail);
                        break;
                    case InspectionType.TransformationRatio:
                        var transformationRatios = _transformationRatioRep.DetachedEntities.Where(s => s.ExperimentTaskId == id).ToList();
                        detail.SetpName = inspectionType.GetDescription();
                        detail.IsCompleted = transformationRatios.Count > 0;
                        detail.IsPass = transformationRatios.Where(s => s.Result == ExperimentResult.NoPass).Count() > 0 ? false : true;
                        items.Add(detail);
                        break;
                    case InspectionType.LoadTest:
                        var loadTests = _loadTestRep.DetachedEntities.Where(s => s.ExperimentTaskId == id).ToList();
                        detail.SetpName = inspectionType.GetDescription();
                        detail.IsCompleted = loadTests.Count > 0;
                        detail.IsPass = loadTests.Where(s => s.Result == ExperimentResult.NoPass).Count() > 0 ? false : true;
                        items.Add(detail);
                        break;
                    case InspectionType.NoLoadTest:
                        var noLoadTests = _noLoadTestRep.DetachedEntities.Where(s => s.ExperimentTaskId == id).ToList();
                        detail.SetpName = inspectionType.GetDescription();
                        detail.IsCompleted = noLoadTests.Count > 0;
                        detail.IsPass = noLoadTests.Where(s => s.Result == ExperimentResult.NoPass).Count() > 0 ? false : true;
                        items.Add(detail);
                        break;
                    case InspectionType.InsulationResistance:
                        var insulationResistances = _insulationResistanceRep.DetachedEntities.Where(s => s.ExperimentTaskId == id).ToList();
                        detail.SetpName = inspectionType.GetDescription();
                        detail.IsCompleted = insulationResistances.Count > 0;
                        detail.IsPass = insulationResistances.Where(s => s.Result == ExperimentResult.NoPass).Count() > 0 ? false : true;
                        items.Add(detail);
                        break;
                    case InspectionType.AcsdTest:
                        var acsdTests = _acsdTestRep.DetachedEntities.Where(s => s.ExperimentTaskId == id).ToList();
                        detail.SetpName = inspectionType.GetDescription();
                        detail.IsCompleted = acsdTests.Count > 0;
                        detail.IsPass = acsdTests.Where(s => s.Result == ExperimentResult.NoPass).Count() > 0 ? false : true;
                        items.Add(detail);
                        break;
                    case InspectionType.PfwvTest:
                        var pfwvTests = _pfwvRep.DetachedEntities.Where(s => s.ExperimentTaskId == id).ToList();
                        detail.SetpName = inspectionType.GetDescription();
                        detail.IsCompleted = pfwvTests.Count > 0;
                        detail.IsPass = pfwvTests.Where(s => s.Result == ExperimentResult.NoPass).Count() > 0 ? false : true;
                        items.Add(detail);
                        break;
                    case InspectionType.ChromTest:
                        var chromTests = _chromTestRep.DetachedEntities.Where(s => s.ExperimentTaskId == id).ToList();
                        detail.SetpName = inspectionType.GetDescription();
                        detail.IsCompleted = chromTests.Count > 0;
                        detail.IsPass = chromTests.Where(s => s.Result == ExperimentResult.NoPass).Count() > 0 ? false : true;
                        items.Add(detail);
                        break;
                    default:
                        break;
                }
            }
            return items;
        }

        /// <summary>
        /// 完工
        /// </summary>
        [HttpPost("experimentTask/completed")]
        [UnitOfWork]
        public async Task Completed(CompletedInput completedInput)
        {
            var experimentTask = await _experimentTaskRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == completedInput.ExperimentTaskId);
            if (experimentTask == null)
                throw Oops.Oh("不存在此数据！");

            //合格需校验试验数据是否采集
            if (completedInput.TaskResult == ExperimentResult.Pass)
            {
                var steps = await GetTaskSteps(experimentTask.Id);
                var isNotCompleteds = steps.Where(s => !s.IsCompleted).ToList();
                if (isNotCompleteds.Count > 0)
                {
                    var msg = $"该任务还有{string.Join(",", isNotCompleteds.Select(s => s.SetpName))}数据未采集，请全部完成后再报工！";
                    throw Oops.Oh(msg);
                }
            }
            experimentTask.Status = ExperimentStatus.Finished;
            experimentTask.Result = completedInput.TaskResult;
            experimentTask.ActualEndTime = DateTime.Now;
            await experimentTask.UpdateNowAsync();

            // 更新试验计划状态
            var experimentTasks = await _experimentTaskRep.DetachedEntities.Where(s => s.ExperimentPlanId == experimentTask.ExperimentPlanId && s.Status != ExperimentStatus.Finished).ToListAsync();
            if (experimentTasks.Count == 0)
            {
                var experimentPlan = await _experimentPlanRep.DetachedEntities.FirstOrDefaultAsync(s => s.Id == experimentTask.ExperimentPlanId);
                experimentPlan.PlanStatus = ExperimentPlanStatus.Finished;
                await _experimentPlanRep.UpdateIncludeAsync(entity: experimentPlan, new[] { nameof(ExperimentPlan.PlanStatus) });
            }
            if (completedInput.TaskResult == ExperimentResult.NoPass)
            {
                //添加不良品处理记录
                AddRejectDealInput addRejectDealInput = new AddRejectDealInput();
                addRejectDealInput.ExperimentTaskId = completedInput.ExperimentTaskId;
                addRejectDealInput.Items = completedInput.RejectItems;

                await _rejectDealServiceRep.Add(addRejectDealInput);
            }
        }

    }
}
